use std::{net::SocketAddr, time::Duration};

use base_data::channel::{event::ChannelEvent, Channel, ChannelState, EndReason};
use time::OffsetDateTime;
use tokio::sync::mpsc::error::TryRecvError;
use tools::{error::Error, utils::current_data_time_with_zone};
use tracing::{debug, info, trace};

use crate::{
	business::{bus_trait::Business, NodeInfo, NodeType, RunContext, TurnNumInfo},
	config::platform_id,
	db::persistence::InboundDBO,
};

#[derive(Debug)]
///呼入的处理过程当中的上下文信息
pub struct InboundRunContext {
	///对应的外部转接号码，显示用
	pub external_num: String,
	///话费/分钟
	pub talk_rate: f32,
	///金额
	pub money: f32,
	///最大限制通话时长
	pub max_limit_call_time: i32,
	///同时呼叫限制？
	pub phone_count: i32,
	///状态信息
	pub flag: i32,
	///主叫区号
	pub caller_area: (String, String),
	pub business_state: BusinessState,
	///业务开始时间,即业务创建时间
	pub call_start_time: OffsetDateTime,
	///本次呼叫开始时间.指最后一次呼叫的开始时间
	pub now_call_time: OffsetDateTime,
	///开始记费时间..此值只关注计费,而不是业务
	pub charge_time: Option<OffsetDateTime>,
	///通话开始时间
	pub talk_start_time: Option<OffsetDateTime>,
	caller_channel: Channel,
	pub called_channel: Option<Channel>,
	pub rec_file_name: Option<String>,
	///整个通话对应的id
	pub ch_call_id: String,
	pub node_info: NodeInfo,
	///一个临时保存的时间值,需要用到的处理节点应该自己赋值
	/// 一般用来做检查时间
	pub check_time: Duration,
	///临时使用的计数器.需要用到的处理节点应该自己赋值
	pub temp_count: i32,
	///针对sip转接的额外信息
	pub sip_tran_info: Option<SocketAddr>,
	pub next_handler: Option<&'static dyn Business<C = InboundRunContext>>,
	pub dtmf: String,
	pub turn_num: TurnNumInfo,
}

impl RunContext for InboundRunContext {
	fn take_next_handler(&mut self) -> Option<&'static dyn Business<C = Self>> {
		self.next_handler.take()
	}
}

impl InboundRunContext {
	#[inline]
	pub fn now_called_num<'a>(&'a self) -> &'a str {
		&self.turn_num.num
	}
	#[inline]
	pub fn set_dtmf(&mut self, dtmf: char) {
		self.dtmf.push(dtmf);
	}

	#[inline]
	pub fn clear_dtmf(&mut self) {
		self.dtmf.clear();
	}
	#[inline]
	pub fn is_bridge(&self) -> bool {
		self.business_state == BusinessState::Talk
	}

	pub fn caller_id(&self) -> u32 {
		self.caller_channel.id
	}

	pub fn caller_channel(&self) -> &Channel {
		&self.caller_channel
	}
	pub fn caller_channel_mut(&mut self) -> &mut Channel {
		&mut self.caller_channel
	}

	pub fn called_channel_mut(&mut self) -> Option<&mut Channel> {
		self.called_channel.as_mut()
	}

	pub fn called_channel_take(&mut self) -> Option<Channel> {
		self.called_channel.take()
	}

	pub fn called_channel_try_recv(&mut self) -> Result<ChannelEvent, TryRecvError> {
		match self.called_channel {
			Some(ref mut cc) => cc.try_recv(),
			None => Err(TryRecvError::Empty),
		}
	}

	#[inline]
	pub fn called_state(&self) -> ChannelState {
		match &self.called_channel {
			Some(ch) => ch.state(),
			None => ChannelState::Down,
		}
	}

	#[inline]
	pub fn caller_state(&self) -> ChannelState {
		self.caller_channel.state()
	}

	pub fn called_channel(&self) -> Option<&Channel> {
		self.called_channel.as_ref()
	}

	pub fn called_num<'a>(&'a self) -> &'a str {
		match &self.called_channel {
			Some(ch) => ch.dest_num(),
			None => "",
		}
	}

	pub fn called_id(&self) -> u32 {
		match &self.called_channel {
			Some(ch) => ch.id(),
			None => 0,
		}
	}

	///对整个逻辑来说呼入的主叫号码
	#[inline]
	pub fn caller_num(&self) -> &str {
		self.caller_channel.caller_num()
	}

	///返回当前呼叫的目的码
	#[inline]
	pub fn target(&self) -> &str {
		self.caller_channel.dest_num()
	}

	///设置被叫的信息
	#[inline]
	pub fn set_start_called_info(&mut self) {
		self.now_call_time = current_data_time_with_zone();
	}

	///创建一个新的上下文
	///
	/// 返回NotFound原因是没有找到对应的信息
	pub async fn new(channel: Channel) -> Result<InboundRunContext, (Channel, Error)> {
		let call_time = current_data_time_with_zone();
		let ch_call_id = format!(
			"{}{}{}",
			call_time.unix_timestamp(),
			platform_id(),
			channel.id
		);

		let mut ct = Self {
			external_num: String::new(),
			talk_rate: 0.0,
			money: 0.0,
			max_limit_call_time: 0,
			phone_count: 0,
			flag: 0,
			caller_area: ("0000".to_owned(), String::default()),
			business_state: BusinessState::Prepare,
			charge_time: None,
			rec_file_name: None,
			now_call_time: call_time,
			ch_call_id,
			talk_start_time: None,
			caller_channel: channel,
			called_channel: None,
			call_start_time: call_time,
			node_info: NodeInfo::default(),
			check_time: Duration::ZERO,
			next_handler: None,
			sip_tran_info: None,
			dtmf: String::default(),
			turn_num: Default::default(),
			temp_count: 0,
		};

		match InboundDBO::load_target_info_set_context(&mut ct).await {
			Ok(_) => Ok(ct),
			Err(e) => {
				info!("加载业务信息失败：{}", e);
				Err((ct.caller_channel, e))
			}
		}
	}

	///判断当前节点是否为空节点
	#[inline]
	pub fn node_is_empty(&self) -> bool {
		let node = &self.node_info;
		match node.node_type {
			NodeType::IVR => false,
			NodeType::Call => node.turn_nums.is_empty(),
		}
	}
	///此次通话是否已经在计费中
	#[inline]
	pub fn is_charging(&self) -> bool {
		self.charge_time.is_some()
	}

	///开始通话的上下文操作
	#[inline]
	pub fn start_talk(&mut self) {
		self.start_charge();
		self.business_state = BusinessState::Talk;
		self.talk_start_time = Some(current_data_time_with_zone());
	}

	///开始通话的计费.已经在计费则不再操作
	#[inline]
	pub fn start_charge(&mut self) {
		if self.charge_time.is_none() {
			debug!("开始计费");
			self.charge_time = Some(current_data_time_with_zone());
		} else {
			trace!(
				"已经开始计费，不能再次进行计费操作。时间：{:?}",
				&self.charge_time
			);
		}
	}

	pub fn is_empty(&self) -> bool {
		self.external_num.is_empty()
	}

	///返回是否已经应答过主叫
	#[inline]
	pub fn is_answered_caller(&self) -> bool {
		self.caller_channel.state == ChannelState::Answered
	}

	pub fn talk_rate(&self) -> f32 {
		self.talk_rate
	}

	pub(crate) fn called_channel_set(&mut self, o_ch: Channel) {
		self.called_channel = Some(o_ch);
	}
}

///业务逻辑的状态
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BusinessState {
	///业务启动,一般来说是接到一个呼入
	Prepare,
	StartBusiness,
	///ivr,等待客户
	WaitDtmf,
	///开始外呼
	StartCallOutbound,
	///通话开始
	Talk,
	///业务结束
	End(EndReason),
}
